#include "chatmanager.h"
#include "constantapp.h"
#include "profilemanager.h"
#include "converse/conversemanager.h"
#include "converse/converseabstractconversation.h"
#include "converse/converseprivateconversation.h"
#include "converse/conversegroupconversation.h"
#include "account/accountuser.h"
#include "sqlite/sessiontable.h"
#include "sqlite/sqlitemanager.h"
#include "sqlite/friendprofiletable.h"
#include "sqlite/userconfigtable.h"
#include "sqlite/messagetable.h"
#include "sqlite/messagedetailtable.h"
#include "sqlite/conversationtable.h"
#include "sqlite/messageunsenttable.h"


#include <QDateTime>
#include <QDebug>

ChatManager *ChatManager::m_instance = NULL;

ChatManager *ChatManager::instance(QObject *parent)
{
    if (m_instance == NULL)
        m_instance = new ChatManager(parent);
    return m_instance;
}

ChatManager::ChatManager(QObject *parent)
    :QObject(parent)
{
    init();
}

void ChatManager::init()
{
    qDebug() << " ChatManager::init()";

    Sqlite::SqliteManager::instance();

    Sqlite::SessionTable::createTable();
    Sqlite::FriendProfileTable::createTable();
    Sqlite::FriendProfileTable::createTableFTS();
    Sqlite::UserConfigTable::createTable();
    Sqlite::MessageTable::createTable();
    Sqlite::MessageDetailTable::createTable();
    Sqlite::ConversationTable::createTable();
    Sqlite::MessageUnsentTable::createTable();

    Contact::Manager::instance();
    Converse::Manager::instance();

    connect (AccountManager::instance(),
             &AccountManager::logined,
             this,
             &ChatManager::onLogined);

    connect (AccountManager::instance(),
             &AccountManager::logouted,
             this,
             &ChatManager::onLogouted);

    connect (Converse::Manager::instance(),
             &Converse::Manager::messageReadFromLocal,
             this,
             &ChatManager::onMessageReadFromLocal);

    connect (Converse::Manager::instance(),
             &Converse::Manager::messageSend,
             this,
             &ChatManager::onMessageSend);


    connect (Converse::Manager::instance(),
             &Converse::Manager::messageReceived,
             this,
             &ChatManager::onMessageReceived);

    connect (Converse::Manager::instance(),
             &Converse::Manager::messageSent,
             this,
             &ChatManager::onMessageSent);

    connect (Converse::Manager::instance(),
             &Converse::Manager::dataInserted,
             this,
             &ChatManager::onDataInserted);
}


void ChatManager::onLogined(bool successed, const QString &message, const QString &sessionKey)
{
    qint64 uid = AccountManager::instance()->getUserId();

    Sqlite::SessionTable::updateSession(uid,sessionKey );
    m_activeUid =  uid;

    emit logined(successed, uid);

}

void ChatManager::onLogouted()
{
    emit logouted();
}

void ChatManager::onDataInserted(int index, Converse::MessageGroup *messageGroup)
{
    Q_UNUSED(index);

    emit insertMessageGroup(messageGroup);

    qDebug() << "ChatManager:: insert new group" + QVariant(messageGroup->senderId()).toString();
}

void ChatManager::onMessageReadFromLocal(AbstractMessage *message)
{
    emit messageReadFromLocal(message);
    qDebug() << "=======================ChatManager::messageReadFromLocal " + message->message();
}

void ChatManager::onMessageSent(Converse::AbstractMessage *message)
{
    qDebug() << "=======================ChatManager::onMessageSent " + message->message();
    emit messageSent(message);

}
void ChatManager::onMessageSend(Converse::AbstractMessage *message)
{
    qDebug() << "=======================ChatManager::onMessageSend " + message->message();
    emit messageSend(message);
}
void ChatManager::onMessageReceived(Converse::AbstractMessage *message)
{
    qDebug() << "=======================ChatManager::onMessageReceived " + message->message();
    emit messageReceived(message);
}

void ChatManager::onRequestBuddiesFinished()
{
    emit requestBuddiesFinished();
}


void ChatManager::doLogin(QString username, QString password)
{
    if (!AccountManager::instance()->login(username, password)) {
        qDebug() << "Login failed. Please try again";
    }
}

void ChatManager::doCreateNewAccount(QString phone, QString code)
{
    if (!AccountManager::instance()->createNewAccount(phone, code)) {
        qDebug() << "create new account failed. Please try again";
    }
}

void ChatManager::doGetActiveCode(QString phone)
{
    if (!AccountManager::instance()->getActiveCodeRequest(phone)) {
        qDebug() << "phone failed. Please try again";
    }
}

void ChatManager::doLogout()
{
    AccountManager::instance()->clearData();
    Contact::Manager::instance()->clearData();
    Converse::Manager::instance()->clearData();
    ProfileManager::instance()->clearData();

    emit logouted();
}

void ChatManager::getHistoryMessageFromLocal(qint64 uid, qint64 buddyId)
{
    if (m_activeConversation == NULL) {
        updatePrivateContactData(buddyId);
    }

    Q_ASSERT(m_activeConversation);
    Converse::AbstractConversation *conversation = \
            m_activeConversation.data();
    Q_ASSERT(conversation);


    Sqlite::MessageTable::getMessageFromLocal(uid, buddyId, -1, 30, conversation);
}

void ChatManager::updatePrivateContactData(qint64 buddyId)
{
    m_activeFid = buddyId;

    m_activeContact = Contact::Manager::instance()->findPrivateContactById(buddyId);

    if (m_activeContact == NULL)
        return;

    Q_ASSERT(m_activeContact);
    Contact::PrivateContact *privateContact = static_cast<Contact::PrivateContact *>(m_activeContact.data());
    Q_ASSERT(privateContact);


    Converse::PrivateConversation *privateConversation = \
            Converse::Manager::instance()->findPrivateConversationByPartnerId(privateContact->id());
    if (privateConversation != NULL) {
        m_activeConversation = privateConversation;
        return;
    }

    // Append private conversation
    Converse::AbstractConversation *conversation
            = Converse::Manager::instance()->appendPrivateConversation(privateContact->id(),
                                                                       privateContact);
    if (conversation == NULL)
        return;
    m_activeConversation = conversation;

    //m_activeConversation.data()->postGetHistoryRequest(30);
    //ui->conversationWidget->view()->getConversation()->postGetHistoryRequest(30);
}

void ChatManager::updateGroupContactData(qint64 groupId)
{
    m_activeFid = groupId;

    m_activeContact = Contact::Manager::instance()->findGroupContactById(groupId);

    if (m_activeContact == NULL)
        return;

    Q_ASSERT(m_activeContact);
    Contact::GroupContact *groupContact = static_cast<Contact::GroupContact *>(m_activeContact.data());
    Q_ASSERT(groupContact);


    Converse::GroupConversation *groupConversation = \
            Converse::Manager::instance()->findGroupConversationByPartnerId(groupContact->id());
    if (groupConversation != NULL) {
        m_activeConversation = groupConversation;
        return;
    }

    // Append group conversation
    Converse::AbstractConversation *conversation
            = Converse::Manager::instance()->appendGroupConversation(groupContact->id(),
                                                                     groupContact);

    if (conversation == NULL)
        return;
    m_activeConversation = conversation;
}

void ChatManager::sendMessage(QString message)
{
    if (message.length() == 0)
        return;

    qint64 createdTime = QDateTime::currentMSecsSinceEpoch() / 1000;
    if (m_activeConversation == NULL) {
        if (m_activeContact == NULL)
            return;

        if (m_activeContact->type() == Contact::AbstractContact::PrivateType) {
            Contact::PrivateContact *privateContact = \
                    dynamic_cast<Contact::PrivateContact *>(m_activeContact.data());
            Q_ASSERT(privateContact);

            Converse::AbstractConversation *conversation
                    = Converse::Manager::instance()->appendPrivateConversation(createdTime, privateContact);
            if (conversation == NULL)
                return;

            m_activeConversation = conversation;
        }
    }

    if (m_activeContact.data()->type() == Contact::AbstractContact::PrivateType) {
        m_activeConversation.data()->send(message, createdTime);
    } else if (m_activeContact.data()->type() == Contact::AbstractContact::GroupType) { // GroupType
        m_activeConversation.data()->sendGroup(message, createdTime);
    }

}

